import React, { useEffect, useState } from 'react';
import type { ReactNode, MouseEvent } from 'react';
import type { ProColumns } from '@ant-design/pro-table';
import { EditableProTable } from '@ant-design/pro-table';
import { Button, Checkbox, DatePicker, Input, InputNumber, message, Select, Space } from 'antd';
import type { FieldType } from './type';
import moment from 'moment';

import styles from './style.less';
import { getLabel, TYPE } from '@/constants';
import type { ValueLabelType } from '@/constants';
import EnhancedInput from '@/sula-plugin/field-plugin/EnhancedInput';
import SelectArtist from '@/components/BaseForm/SelectArtist';
import type { CheckboxChangeEvent } from 'antd/lib/checkbox';
import { isEqual } from 'lodash';
import { isSingersEqual } from '@/utils/utils';
import SingerTxtSelect from '../BaseForm/SingerTxtSelect';
import FileUpload from '../FileUpload';

type Props = {
  moduleTitle: string;
  rowKey: string;
  loading: boolean;
  selectedFields: string[];
  inEditMode: boolean;
  dataSource: any[];
  recordList: any[];
  fieldsConfig: FieldType[];
  getExtraUpdateParams?: (result: any, nestedResult: any) => any;
  changeToEdit: () => void;
  onDataChange: (dataSource: any[]) => void;
  batchUpdate: (data: any) => Promise<any>;
  onBatchSaved: () => void;
};

const EditTable: React.FC<Props> = ({
  moduleTitle,
  rowKey,
  loading,
  selectedFields,
  inEditMode,
  dataSource,
  recordList,
  fieldsConfig,
  getExtraUpdateParams,
  changeToEdit,
  onDataChange,
  batchUpdate,
  onBatchSaved,
}) => {
  const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
  const [columns, setColumns] = useState<ProColumns[]>([]);
  const [saving, setSaving] = useState(false);
  const [batchMatchValues, setBatchMatchValues] = useState<Record<string, any>>({});
  const [batchEdit, setBatchEdit] = useState(false);

  useEffect(() => {
    if (!inEditMode) {
      setEditableRowKeys([]);
    }
  }, [inEditMode]);

  const renderControl = (item: FieldType, value?: any) => {
    if (!item) {
      return null;
    }
    const { options, ...rest } = item.componentOptions || {};
    if (item.type === TYPE.SELECT) {
      return (
        <Select
          value={batchMatchValues[item.field]}
          onChange={(fieldValue: string | number) => {
            setBatchMatchValues({ ...batchMatchValues, [item.field]: fieldValue });
          }}
          placeholder={`请选择${item.label}`}
          {...rest}
          className={styles.matchControl}
        >
          {options?.map((option: ValueLabelType) => (
            <Select.Option key={option.value} value={option.value}>
              {option.label}
            </Select.Option>
          ))}
        </Select>
      );
    }
    if (item.type === TYPE.SINGER) {
      return (
        <SelectArtist
          mode="multiple"
          className={styles.matchControl}
          value={batchMatchValues[item.field]}
          onChange={(fieldValue) => {
            setBatchMatchValues({ ...batchMatchValues, [item.field]: fieldValue });
          }}
        />
      );
    }
    if (item.type === TYPE.SINGER_TXT) {
      return (
        <Select
          mode="tags"
          className={styles.matchControl}
          value={batchMatchValues[item.field]}
          onChange={(fieldValue) => {
            setBatchMatchValues({ ...batchMatchValues, [item.field]: fieldValue });
          }}
        />
      );
    }
    if (item.type === TYPE.UPLOAD) {
      return (
        <FileUpload
          value={batchMatchValues[item.field]}
          onChange={(fieldValue) => {
            setBatchMatchValues({ ...batchMatchValues, [item.field]: fieldValue });
          }}
          {...rest}
          type={rest.type || ''}
        />
      );
    }
    if (item.type === TYPE.DATETIME) {
      return (
        <DatePicker
          placeholder="请选择时间"
          value={batchMatchValues[item.field]}
          onChange={(fieldValue) => {
            setBatchMatchValues({ ...batchMatchValues, [item.field]: fieldValue });
          }}
          showTime={{ defaultValue: moment('00:00:00', 'HH:mm:ss') }}
          format="YYYY-MM-DD HH:mm:ss"
          className={styles.matchControl}
        />
      );
    }
    if (item.type === TYPE.NUMBER) {
      return (
        <InputNumber
          id={item.field}
          defaultValue={value}
          placeholder={`请输入${item.label}`}
          style={{ width: '100%' }}
        />
      );
    }
    return <Input id={item.field} defaultValue={value} placeholder={`请输入${item.label}`} />;
  };

  const renderBatchControl = (item: FieldType, value?: any) => {
    if (!item) {
      return null;
    }
    return (
      <Input.TextArea
        id={`batch_${item.field}`}
        defaultValue={value}
        placeholder={`请输入${item.label}`}
        className={styles.batchControl}
        disabled={[TYPE.SINGER_TXT, TYPE.SINGER, TYPE.UPLOAD].includes(item.type)}
      />
    );
  };

  const renderFormItem = (item: FieldType) => {
    return item.type !== TYPE.DATETIME
      ? () => {
          const { options, ...rest } = item.componentOptions || {};
          if (item.type === TYPE.SELECT) {
            return (
              <Select placeholder={`请选择${item.label}`} {...rest}>
                {options?.map((option: ValueLabelType) => (
                  <Select.Option key={option.value} value={option.value}>
                    {option.label}
                  </Select.Option>
                ))}
              </Select>
            );
          }
          if (item.type === TYPE.SINGER) {
            return <SelectArtist mode="multiple" />;
          }
          if (item.type === TYPE.SINGER_TXT) {
            return <SingerTxtSelect />;
          }
          if (item.type === TYPE.UPLOAD) {
            return <FileUpload {...rest} type={rest.type || ''} />;
          }
          if (item.type === TYPE.NUMBER) {
            return <InputNumber placeholder={`请输入${item.label}`} style={{ width: '100%' }} />;
          }
          return <EnhancedInput placeholder={`请输入${item.label}`} />;
        }
      : undefined;
  };

  const getDataSourceField = (
    originDataSource: any,
    keyData: string | number,
    fieldName: string,
  ) => {
    return originDataSource.find((item: any) => item[rowKey] === keyData)?.[fieldName];
  };

  const render = (item: FieldType, originDataSource: any) => (_: ReactNode, entity: any) => {
    const { options } = item.componentOptions || {};
    let field = entity[item.field];
    const dataSourceField = getDataSourceField(originDataSource, entity[rowKey], item.field);
    const labelClass = isEqual(field, dataSourceField) ? '' : 'dangerWord';
    if (item.type === TYPE.SELECT) {
      if (item.componentOptions?.mode === 'multiple' || item.componentOptions?.mode === 'tags') {
        if (typeof field === 'string') {
          field = field.split(',').map(Number);
        }
        return (
          <span className={labelClass}>
            {field?.map((fieldData: string | number, index: number) => (
              <span key={fieldData}>
                <span>{getLabel(fieldData, options || [])?.split('.')[1]}</span>
                {index < field.length - 1 ? '、' : ''}
              </span>
            ))}
          </span>
        );
      }
      return <span className={labelClass}>{getLabel(field, options || [])?.split('.')[1]}</span>;
    }
    if (item.type === TYPE.SINGER) {
      const singersLabelClass = isSingersEqual(field, dataSourceField) ? '' : 'dangerWord';
      return (
        <span className={singersLabelClass}>
          {field?.map((singer: any, index: number) => {
            return `${singer.singerName}(${singer.singerId})${
              index < field.length - 1 ? '、' : ''
            }`;
          })}
        </span>
      );
    }
    if (item.type === TYPE.SINGER_TXT) {
      const singersLabelClass = isSingersEqual(field, dataSourceField) ? '' : 'dangerWord';
      return (
        <span className={singersLabelClass}>
          {field?.map((singer: any, index: number) => {
            return `${singer.singerName}(${singer.singerId})${
              index < field.length - 1 ? '、' : ''
            }`;
          })}
        </span>
      );
    }
    if (item.type === TYPE.UPLOAD) {
      return (
        <span className={labelClass}>
          {field &&
            field.map(({ fileName }: any, index: number) => {
              return `${fileName}${index < field.length - 1 ? '、' : ''}`;
            })}
        </span>
      );
    }

    return <span className={labelClass}>{field}</span>;
  };

  const onHeaderCell = (item: FieldType) => () => {
    const value = (document.getElementById(item.field) as HTMLInputElement)?.value || '';
    const batchValue =
      (document.getElementById(`batch_${item.field}`) as HTMLInputElement)?.value || '';
    return {
      title: item.field,
      value: {
        item,
        value,
        batchValue,
      },
    };
  };

  const fieldProps = (item: FieldType) => () => {
    return item.type === TYPE.DATETIME
      ? {
          style: { width: '100%' },
          showTime: { defaultValue: moment('00:00:00', 'HH:mm:ss') },
          format: 'YYYY-MM-DD HH:mm:ss',
        }
      : undefined;
  };

  useEffect(() => {
    setBatchMatchValues(
      fieldsConfig.reduce((result, item) => {
        const data = { ...result };
        if (item.type === TYPE.SELECT && item.componentOptions?.defaultValue !== undefined) {
          data[item.field] = item.componentOptions?.defaultValue;
        }
        return data;
      }, {}),
    );
  }, [fieldsConfig]);

  useEffect(() => {
    const fields: ProColumns<any>[] = [];
    fieldsConfig.forEach((item) => {
      if (item.tableShow || selectedFields.some((selectedField) => selectedField === item.field)) {
        fields.push({
          title: item.label,
          dataIndex: item.field,
          width: item.width || 200,
          fixed: item.fixed,
          editable: () => item.editable !== false,
          valueType: item.type === TYPE.DATETIME ? 'dateTime' : undefined,
          onHeaderCell: onHeaderCell(item),
          renderFormItem: renderFormItem(item),
          fieldProps,
          render: render(item, dataSource),
        });
      }
    });
    setColumns(fields);
  }, [selectedFields, dataSource]);

  const getFieldSaveValue = (key: string, value: any) => {
    const field = fieldsConfig.find((item) => item.field === key);
    return field?.format2Backend ? field?.format2Backend(value) : value;
  };

  const onSave = async () => {
    setSaving(true);
    const data: any[] = recordList.map((item) => {
      const nestedResult: any = {};
      const ret: any = Object.keys(item).reduce((result, key) => {
        const res = { ...result };
        if (!key.includes('.')) {
          res[key] = getFieldSaveValue(key, item[key]);
        } else {
          const keys = key.split('.');
          if (nestedResult[keys[0]] === undefined) {
            nestedResult[keys[0]] = {};
          }
          nestedResult[keys[0]][keys[1]] = getFieldSaveValue(key, item[key]);
        }
        return res;
      }, {});
      return {
        ...ret,
        ...nestedResult,
        ...(getExtraUpdateParams?.(ret, nestedResult) || {}),
      };
    });
    try {
      await batchUpdate(data);
      message.success('批量编辑成功');
      onBatchSaved();
      setSaving(false);
    } catch (err) {
      setSaving(false);
    }
  };

  const replaceAll = (fieldName: string, fieldType: TYPE) => {
    let data: any;
    if (fieldType === TYPE.SELECT || fieldType === TYPE.SINGER) {
      data = batchMatchValues[fieldName];
    } else if (fieldType === TYPE.SINGER_TXT) {
      data = batchMatchValues[fieldName].map((name: string) => {
        return {
          singerId: 0,
          singerName: name,
        };
      });
    } else if (fieldType === TYPE.DATETIME) {
      data = batchMatchValues[fieldName].format('YYYY-MM-DD HH:mm:ss');
    } else if (fieldType === TYPE.UPLOAD) {
      data = batchMatchValues[fieldName] || [];
    } else {
      data = (document.getElementById(fieldName) as HTMLInputElement).value.trim();
    }
    if (data !== 0 && !data) {
      return;
    }
    onDataChange(
      recordList.map((item) => ({
        ...item,
        [fieldName]: data,
      })),
    );
  };

  const batchReplace = (fieldItem: FieldType, data: string) => {
    const valueList = data.split('\n');
    onDataChange(
      recordList.map((item, index) => {
        const ret = { ...item };
        if (index < valueList.length) {
          if (fieldItem.type === TYPE.SELECT) {
            if (fieldItem.componentOptions?.mode === undefined) {
              ret[fieldItem.field] = fieldItem.componentOptions?.valueString
                ? valueList[index]
                : Number(valueList[index]);
            } else {
              ret[fieldItem.field] = valueList[index].split(',');
            }
          } else {
            ret[fieldItem.field] = valueList[index];
          }
        }
        return ret;
      }),
    );
  };

  const batchMatch = (fieldItem: FieldType) => () => {
    const batchData = (document.getElementById(`batch_${fieldItem.field}`) as HTMLInputElement)
      .value;
    if (batchData.trim() !== '') {
      batchReplace(fieldItem, batchData.trim());
    } else {
      replaceAll(fieldItem.field, fieldItem.type);
    }
  };

  const emptyColumn = (fieldName: string, fieldType: TYPE) => () => {
    let data: any = '';
    if ([TYPE.UPLOAD, TYPE.SINGER, TYPE.SINGER_TXT].includes(fieldType)) {
      data = [];
    }
    onDataChange(
      recordList.map((item) => ({
        ...item,
        [fieldName]: data,
      })),
    );
  };

  const cell = ({ children, title, value: fieldValue, ...rest }: any) => {
    if (fieldValue?.item.type === TYPE.SHOW) {
      return <th {...rest}>{children}</th>;
    }

    return (
      <th {...rest}>
        <div>{children}</div>
        {batchEdit && (
          <Space direction="vertical" className={styles.matchControl}>
            <Space className={styles.operate}>
              <Button size="small" onClick={batchMatch(fieldValue?.item)}>
                批量匹配
              </Button>
              <Button size="small" onClick={emptyColumn(title, fieldValue.item?.type)}>
                清空该列
              </Button>
            </Space>
            {renderControl(fieldValue?.item, fieldValue?.value)}
            {renderBatchControl(fieldValue?.item, fieldValue?.batchValue)}
          </Space>
        )}
      </th>
    );
  };

  const onBatchEditChange = (e: CheckboxChangeEvent) => {
    setBatchEdit(e.target.checked);
  };

  return (
    <EditableProTable<any>
      headerTitle={`${moduleTitle}列表`}
      columns={columns}
      rowKey={rowKey}
      className={styles.editTable}
      value={recordList}
      components={{ header: { cell } }}
      recordCreatorProps={false}
      toolBarRender={() => {
        return [
          <Checkbox checked={batchEdit} onChange={onBatchEditChange}>
            批量修改
          </Checkbox>,
          <Button type="primary" key="save" onClick={onSave} loading={saving}>
            保存
          </Button>,
        ];
      }}
      editable={{
        type: 'multiple',
        editableKeys,
        onValuesChange: (_, records) => {
          onDataChange(records);
        },
        onChange: setEditableRowKeys,
      }}
      scroll={{ x: 1200 }}
      loading={loading}
      onRow={(record: any) => {
        return {
          onClick: (e: MouseEvent<HTMLElement>) => {
            e.stopPropagation();
            changeToEdit();
            setEditableRowKeys([record[rowKey]]);
          },
        };
      }}
    />
  );
};

export default EditTable;
